﻿package nsga;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import algorithm.AlgCtx;
import control.CtrlEngine;
import control.ExeCtx;
import control.PerfEvaluator;
import foundation.SurModel.rndForest.sample.MLearnTbl;
import foundation.SurModel.rndForest.sample.PerfLearnTblItem;
import foundation.concurrency.Product;
import foundation.fileUtil.DataCell;
import foundation.fileUtil.ExcelUtil;
import abstractGA.AbsGAAlg;
import abstractGA.OutGAResultThread;
import abstractGA.OutPopuThread;
import abstractGA.PopuData;
import abstractGA.chrom.Chrom;
import abstractGA.popu.PopuBuilder;
import abstractGA.popu.Population;


public class NSGAAlg extends AbsGAAlg {
	boolean isFinish = false;
	/**
	 * 构造函数
	 * @param popuBld：种群构造器
	 */
	public NSGAAlg(PopuBuilder popuBld) {
		super(popuBld);
	}

	@Override
	public void run(AlgCtx algCtx,int runNum, String rltFlNm) {
		//记录一次运行开始时间
		SimpleDateFormat  startDate = new SimpleDateFormat("yyyy-MM-dd_kk-mm-ss");
		String startTime= startDate.format(new Date());
		
		ArrayList<String> runIDs = new ArrayList<String>();
		// 保存PareTo最优染色体集
		List<Chrom> bestChroms = null;
		OutGAResultThread algOutThrd = null;
		for (int i = 1; i <= runNum; i++) {
			System.out.println("NSGA算法第" + i + "次开始运行.......");
			init(algCtx);
			int maxItem = parameter.getMaxIterNum();// 一次运行最多演化代数
			//演化产生的种群数据需要送数据库，已考虑并发读写
			Product<PopuData> prod = new Product<PopuData>();
			prod.setMaxNum(maxItem);
			
			//这里改了
			OutPopuThread consummer = new OutPopuThread(prod, algCtx, outData);
			consummer.start();
			
			UUID uuid = UUID.randomUUID();// GUID
			String runID = algCtx.getAlgName() + uuid.toString();
			runIDs.add(runID);
			int genNum = 1;// 演化代数
			while (genNum <= maxItem) {
				if(genNum==maxItem){
					ExeCtx exeCtx = ((CtrlEngine)algCtx.getAlgOper()).getExeCtx();
					exeCtx.setUseMLearn(false);
				}
				// 交配选择操作,产生临时种群
				Population tempPopu = curPopu.mutingChoose();
				// 进行单点交叉操作
				tempPopu.crossover(1);
				// 进行单点均匀变异操作
				tempPopu.mutate(1);
				// 环境选择
				Population nxtPopu = curPopu.envSelect(tempPopu);
				bestChroms = nxtPopu.getBestChroms();
				delRepChrom(bestChroms);// 删除重复最优解
//				outBestChroms(bestChroms);
				curPopu = nxtPopu;				
				// 输出种群到数据库
				PopuData data = new PopuData();
				data.setRunID(runID);
				data.setGenID(String.valueOf(genNum));
				data.setCurPopu(curPopu.copy());// 避免种群被修改	
				prod.addData(data);
				genNum++;		
			}
			//等待算法运行一次后插入数据库完成
			while(!isFinished){
				isFinished=consummer.isFinish();
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			System.out.println("本次运行" + genNum + "代");
		}
		//记录一次运行结束时间
		SimpleDateFormat  endDate = new SimpleDateFormat("yyyy-MM-dd_kk-mm-ss");
		String endTime= endDate.format(new Date());
		//拼凑.xls格式
		rltFlNm = rltFlNm + "_startTime=" + startTime + "_endTime=" + endTime + ".xls";
		// 算法结果输出到excel文件
		algOutThrd = new OutGAResultThread(outData, parameter, rltFlNm, runIDs);
		algOutThrd.outToExcel(startTime, endTime);
//		algOutThrd.start();// 后台运行
//		try {
//			algOutThrd.join(0);// 参数为0表示等待algOutThrd线程一直运行结束,
//		} catch (InterruptedException e) {
//			e.printStackTrace();
//		}
		
		// 输出机器学习表
		//*************
		
		int index = rltFlNm.lastIndexOf("\\");
		int index2 = rltFlNm.indexOf("_");
		String host = rltFlNm.substring(index + 1, index2);
		// 从excel路径中获取案例名
		String[] a = rltFlNm.split("_");
		String caseName = a[1];
		// 从excel路径中获取算法名
		String algNm = a[2];
		MLearnTbl mltbl = MLearnTbl.getInstance();

		CtrlEngine ctrlEngine = (CtrlEngine) algCtx.getAlgOper();
		completionPerfTbl(mltbl.getPerfSamTbl(), ctrlEngine);
		int size = runIDs.size();
		mltbl.outPerfTblToDB(runIDs.get(size - 1));// qing xiao bin xu gai
		List<List<DataCell>> perfSMQul = mltbl.outPerfSMQul(runIDs.get(size - 1), host, caseName, algNm);
		// String path = FileNameUtil.getPrjPath();
		// path = path+"demo\\jssbrs\\runFiles\\resultFiles\\perfSMQul.xls";
		ExcelUtil.write(rltFlNm, perfSMQul);
		mltbl.clearML();
		outData.closeDBConn();// 关闭数据库连接
	}
	
	/**
	 * 将预测阶段每个编码的预测值对应真实值进行求解并补充填入机器学习表
	 * @param perfTbl：机器学习表
	 * @param rulCtrlEngine：规则控制引擎
	 */
	public void completionPerfTbl(ArrayList<PerfLearnTblItem> perfTbl, CtrlEngine ctrlEngine) {
		PerfEvaluator perfElvor = ctrlEngine.getPerfElvor();
		ExeCtx exeCtx = ctrlEngine.getExeCtx();
		//设置初始上下文
//		RulCtrlEngHelper rulCtrlHlper = ctrlEngine.getRulCtrlHlper();
//		List<StringBuffer> initFdCodes = rulCtrlHlper.getInitFdCodes();
//		exeCtx.setInitExeCtx(initFdCodes);
		//删除最后一轮只经过解析而未被预测的数据
		for(int i=0;i<perfTbl.size();i++){
			boolean beenSolved = perfTbl.get(i).getActualresTime()>0;
			boolean notBbeenPredict = perfTbl.get(i).getPredictResTime()==-1;
			
			if(beenSolved && notBbeenPredict){
				perfTbl.remove(perfTbl.get(i));
				i--;
			}
		}
		
		//补全只经过预测而未被真实解析的值
		for (PerfLearnTblItem curPerfItem : perfTbl) {
			 if (curPerfItem.getActualresTime() == -1) {
				// 获取当前机器学习的自由度实例编码
				List<StringBuffer> mlDfCodes = curPerfItem.getMlDFcodes();
				// 转换成自由度实例编码
				List<StringBuffer> newDfCodes = exeCtx.ml2DfCodes(mlDfCodes);
				// 根据新自由度实例获取性能指标
				exeCtx.getSaInfo().mdfySA(newDfCodes);
				
				PerfLearnTblItem perfItem = perfElvor.getPerfIndicesBySolve();
				// 刷新当前性能指标样本表项
				curPerfItem.setActualresTime(perfItem.getActualresTime());
			}
		}
	}



	public void outBestChroms(List<Chrom> bestChroms) {
		System.out
				.println("===================================================");
		for (Chrom chrom : bestChroms) {
			System.out.println(chrom.outChrom());
		}
		System.out
				.println("===================================================");
	}

	public void delRepChrom(List<Chrom> bestChroms) {
		for (int i = 0; i < bestChroms.size(); i++) {
			Chrom chrom1 = bestChroms.get(i);
			for (int j = i + 1; j < bestChroms.size(); j++) {
				Chrom chrom2 = bestChroms.get(j);
				if (chrom2.isEqual(chrom1)) {
					bestChroms.remove(j);
					j = j - 1;
				}
			}
		}
	}
}
